import * as fs from 'fs';
import * as path from 'path';
import { Logger } from '../../src/logger/Logger';

/**
 * 全面代码库索引器
 * 学习整个项目：源码(.h/.cpp)、BUILD.gn、测试、Mock、以及它们之间的关系
 */
export class ComprehensiveIndexer {
    private ohCodePath: string;
    private comprehensiveKnowledge: any = {
        // 项目源码结构
        projectStructures: [],
        
        // 头文件模式
        headerPatterns: [],
        
        // 实现文件模式  
        implPatterns: [],
        
        // 头文件与实现文件的关系
        headerImplRelations: [],
        
        // BUILD.gn 与源码的关系
        gnSourceRelations: [],
        
        // 测试目录完整结构
        testDirStructures: [],
        
        // 测试文件与被测文件的关系
        testTargetRelations: [],
        
        // Mock 文件完整模式
        mockPatterns: [],
        
        // Mock 与原始类的关系
        mockTargetRelations: [],
        
        // 包含关系图
        includeGraph: [],
        
        // 依赖关系图
        dependencyGraph: []
    };

    constructor(ohCodePath: string) {
        this.ohCodePath = ohCodePath;
    }

    /**
     * 执行全面学习
     */
    public async comprehensiveLearn(): Promise<void> {
        Logger.info('\n🎓 全面代码库学习系统 v3.0');
        Logger.info('============================================\n');
        
        const projects = this.discoverProjects();
        Logger.info(`[ComprehensiveIndexer] 发现 ${projects.length} 个 OH 工程`);
        Logger.info(`[ComprehensiveIndexer] 将全面学习每个工程\n`);

        for (const project of projects) {
            await this.learnProjectComprehensive(project);
        }

        // 分析关系
        this.analyzeRelationships();

        Logger.info('\n✅ 全面学习完成！\n');
    }

    /**
     * 发现工程
     */
    private discoverProjects(): any[] {
        const projects: any[] = [];
        
        try {
            const entries = fs.readdirSync(this.ohCodePath, { withFileTypes: true });
            
            for (const entry of entries) {
                if (entry.isDirectory()) {
                    const projectPath = path.join(this.ohCodePath, entry.name);
                    const bundleJsonPath = path.join(projectPath, 'bundle.json');
                    
                    if (fs.existsSync(bundleJsonPath)) {
                        projects.push({
                            name: entry.name,
                            path: projectPath
                        });
                    }
                }
            }
        } catch (error) {
            Logger.error(`发现工程失败: ${error}`);
        }
        
        return projects;
    }

    /**
     * 全面学习单个工程
     */
    private async learnProjectComprehensive(project: any): Promise<void> {
        Logger.info(`[ComprehensiveIndexer] 📚 全面学习: ${project.name}`);

        const structure: any = {
            projectName: project.name,
            projectPath: project.path,
            sourceFiles: {
                headers: [],
                impls: [],
                total: 0
            },
            buildFiles: [],
            testDirs: [],
            mockFiles: []
        };

        // 1. 扫描整个项目结构（排除test目录，先学习源码）
        Logger.info(`[ComprehensiveIndexer]   - 扫描项目源码...`);
        await this.scanProjectSources(project.path, structure, project.name);

        // 2. 学习 test 目录结构
        Logger.info(`[ComprehensiveIndexer]   - 学习测试目录...`);
        await this.learnTestDirectories(project, structure);

        // 3. 分析文件关系
        Logger.info(`[ComprehensiveIndexer]   - 分析文件关系...`);
        await this.analyzeFileRelations(structure);

        this.comprehensiveKnowledge.projectStructures.push(structure);

        Logger.info(`[ComprehensiveIndexer]   ✓ 源文件: ${structure.sourceFiles.total}, 测试目录: ${structure.testDirs.length}, Mock: ${structure.mockFiles.length}`);
    }

    /**
     * 扫描项目源码
     */
    private async scanProjectSources(
        dir: string, 
        structure: any, 
        projectName: string,
        depth: number = 0,
        maxDepth: number = 8
    ): Promise<void> {
        if (depth > maxDepth) return;

        try {
            const entries = fs.readdirSync(dir, { withFileTypes: true });

            for (const entry of entries) {
                const fullPath = path.join(dir, entry.name);

                // 跳过test目录（单独处理）
                if (entry.name === 'test' || entry.name === 'tests') continue;
                
                // 跳过隐藏目录和构建目录
                if (entry.name.startsWith('.') || entry.name === 'out' || entry.name === 'build') continue;

                if (entry.isDirectory()) {
                    await this.scanProjectSources(fullPath, structure, projectName, depth + 1, maxDepth);
                } else if (entry.isFile()) {
                    // 学习源文件
                    if (entry.name.endsWith('.h') || entry.name.endsWith('.hpp')) {
                        const headerInfo = await this.learnHeaderFile(fullPath, projectName);
                        if (headerInfo) {
                            structure.sourceFiles.headers.push(headerInfo);
                            structure.sourceFiles.total++;
                        }
                    } else if (entry.name.endsWith('.cpp') || entry.name.endsWith('.cc')) {
                        const implInfo = await this.learnImplFile(fullPath, projectName);
                        if (implInfo) {
                            structure.sourceFiles.impls.push(implInfo);
                            structure.sourceFiles.total++;
                        }
                    } else if (entry.name === 'BUILD.gn') {
                        const gnInfo = await this.learnBuildGn(fullPath, projectName);
                        if (gnInfo) {
                            structure.buildFiles.push(gnInfo);
                        }
                    }
                }
            }
        } catch (error) {
            // 忽略权限错误
        }
    }

    /**
     * 学习头文件
     */
    private async learnHeaderFile(filePath: string, projectName: string): Promise<any> {
        try {
            const content = fs.readFileSync(filePath, 'utf-8');
            
            const headerInfo = {
                projectName,
                filePath,
                fileName: path.basename(filePath),
                relativePath: filePath.replace(this.ohCodePath, '').replace(/\\/g, '/'),
                
                // 提取类声明
                classes: this.extractClasses(content),
                
                // 提取函数声明
                functions: this.extractFunctions(content),
                
                // 提取 includes
                includes: this.extractIncludes(content),
                
                // 提取命名空间
                namespaces: this.extractNamespaces(content),
                
                // 是否有虚函数
                hasVirtualFunctions: content.includes('virtual '),
                
                // 是否是接口类
                isInterface: content.includes('= 0;'),
                
                // 代码片段
                snippet: content.substring(0, 300)
            };

            this.comprehensiveKnowledge.headerPatterns.push(headerInfo);
            return headerInfo;

        } catch (error) {
            return null;
        }
    }

    /**
     * 学习实现文件
     */
    private async learnImplFile(filePath: string, projectName: string): Promise<any> {
        try {
            const content = fs.readFileSync(filePath, 'utf-8');
            
            const implInfo = {
                projectName,
                filePath,
                fileName: path.basename(filePath),
                relativePath: filePath.replace(this.ohCodePath, '').replace(/\\/g, '/'),
                
                // 提取 includes（找到对应的头文件）
                includes: this.extractIncludes(content),
                
                // 对应的头文件（推测）
                correspondingHeader: this.guessCorrespondingHeader(filePath, content),
                
                // 实现的函数
                implementedFunctions: this.extractImplementedFunctions(content),
                
                // 命名空间
                namespaces: this.extractNamespaces(content),
                
                // 代码片段
                snippet: content.substring(0, 300)
            };

            this.comprehensiveKnowledge.implPatterns.push(implInfo);
            return implInfo;

        } catch (error) {
            return null;
        }
    }

    /**
     * 学习 BUILD.gn
     */
    private async learnBuildGn(filePath: string, projectName: string): Promise<any> {
        try {
            const content = fs.readFileSync(filePath, 'utf-8');
            
            const gnInfo = {
                projectName,
                filePath,
                relativePath: filePath.replace(this.ohCodePath, '').replace(/\\/g, '/'),
                
                // 提取 sources
                sources: this.extractArrayField(content, 'sources'),
                
                // 提取 include_dirs
                includeDirs: this.extractArrayField(content, 'include_dirs'),
                
                // 提取 deps
                deps: this.extractArrayField(content, 'deps'),
                
                // 提取 external_deps
                externalDeps: this.extractArrayField(content, 'external_deps'),
                
                // 是否是测试
                isTest: content.includes('ohos_unittest') || content.includes('ohos_fuzztest'),
                
                // 目标类型
                targetTypes: this.extractTargetTypes(content),
                
                // 代码片段
                snippet: content.substring(0, 500)
            };

            return gnInfo;

        } catch (error) {
            return null;
        }
    }

    /**
     * 学习测试目录
     */
    private async learnTestDirectories(project: any, structure: any): Promise<void> {
        const testDirs = [
            path.join(project.path, 'test'),
            path.join(project.path, 'tests')
        ];

        for (const testDir of testDirs) {
            if (!fs.existsSync(testDir)) continue;

            // 学习 unittest 目录
            const unittestDir = path.join(testDir, 'unittest');
            if (fs.existsSync(unittestDir)) {
                await this.learnUnittestDir(unittestDir, project.name, structure);
            }

            const unittestsDir = path.join(testDir, 'unittests');
            if (fs.existsSync(unittestsDir)) {
                await this.learnUnittestDir(unittestsDir, project.name, structure);
            }

            // 学习 fuzztest 目录
            const fuzztestDir = path.join(testDir, 'fuzztest');
            if (fs.existsSync(fuzztestDir)) {
                await this.learnFuzztestDir(fuzztestDir, project.name, structure);
            }
        }
    }

    /**
     * 学习 unittest 目录
     */
    private async learnUnittestDir(unittestDir: string, projectName: string, structure: any): Promise<void> {
        try {
            const testModules = fs.readdirSync(unittestDir, { withFileTypes: true })
                .filter(d => d.isDirectory() && d.name !== 'resource')
                .map(d => path.join(unittestDir, d.name));

            for (const moduleDir of testModules) {
                const moduleName = path.basename(moduleDir);
                const moduleInfo = await this.learnTestModule(moduleDir, projectName, moduleName, 'unittest');
                
                if (moduleInfo) {
                    structure.testDirs.push(moduleInfo);
                    
                    // 收集 mock 文件
                    for (const mockFile of moduleInfo.mockFiles) {
                        structure.mockFiles.push(mockFile);
                        
                        // 学习 mock 文件内容
                        const mockPattern = await this.learnMockFile(mockFile.filePath, projectName);
                        if (mockPattern) {
                            this.comprehensiveKnowledge.mockPatterns.push(mockPattern);
                        }
                    }
                }
            }
        } catch (error) {
            // 忽略错误
        }
    }

    /**
     * 学习测试模块
     */
    private async learnTestModule(
        moduleDir: string, 
        projectName: string, 
        moduleName: string,
        testType: string
    ): Promise<any> {
        try {
            const files = fs.readdirSync(moduleDir);
            
            const moduleInfo: any = {
                projectName,
                moduleName,
                testType,
                moduleDir,
                
                testFiles: [],
                mockFiles: [],
                buildGn: null,
                
                allFiles: files
            };

            // 收集测试文件
            for (const file of files) {
                const filePath = path.join(moduleDir, file);
                
                if (file.endsWith('_test.cpp') || file.endsWith('_test.cc')) {
                    const testFileInfo = await this.learnTestFile(filePath, projectName);
                    if (testFileInfo) {
                        moduleInfo.testFiles.push(testFileInfo);
                    }
                } else if (file.toLowerCase().includes('mock')) {
                    moduleInfo.mockFiles.push({
                        fileName: file,
                        filePath
                    });
                } else if (file === 'BUILD.gn') {
                    const gnInfo = await this.learnBuildGn(filePath, projectName);
                    moduleInfo.buildGn = gnInfo;
                }
            }

            return moduleInfo;

        } catch (error) {
            return null;
        }
    }

    /**
     * 学习测试文件
     */
    private async learnTestFile(filePath: string, projectName: string): Promise<any> {
        try {
            const content = fs.readFileSync(filePath, 'utf-8');
            
            return {
                projectName,
                filePath,
                fileName: path.basename(filePath),
                
                // 测试类
                testClasses: this.extractTestClasses(content),
                
                // HWTEST_F 用例
                testCases: this.extractTestCases(content),
                
                // 包含的头文件
                includes: this.extractIncludes(content),
                
                // 测试的目标（推测）
                testedTarget: this.guessTestedTarget(filePath, content),
                
                // 使用的Mock
                usedMocks: this.extractUsedMocks(content),
                
                // 命名空间
                namespaces: this.extractNamespaces(content),
                
                // 代码片段
                snippet: content.substring(0, 500)
            };

        } catch (error) {
            return null;
        }
    }

    /**
     * 学习 Mock 文件
     */
    private async learnMockFile(filePath: string, projectName: string): Promise<any> {
        try {
            const content = fs.readFileSync(filePath, 'utf-8');
            
            return {
                projectName,
                filePath,
                fileName: path.basename(filePath),
                
                // Mock 的类
                mockedClasses: this.extractClasses(content),
                
                // MOCK_METHOD
                mockMethods: this.extractMockMethods(content),
                
                // 包含的原始头文件
                includes: this.extractIncludes(content),
                
                // Mock 的目标（推测）
                mockedTarget: this.guessMockedTarget(filePath, content),
                
                // 命名空间
                namespaces: this.extractNamespaces(content),
                
                // 完整内容（Mock文件通常不大）
                fullContent: content.length < 10000 ? content : content.substring(0, 10000)
            };

        } catch (error) {
            return null;
        }
    }

    /**
     * 学习 fuzztest 目录
     */
    private async learnFuzztestDir(fuzztestDir: string, projectName: string, structure: any): Promise<void> {
        try {
            const fuzzerDirs = fs.readdirSync(fuzztestDir, { withFileTypes: true })
                .filter(d => d.isDirectory() && d.name.endsWith('_fuzzer'))
                .map(d => path.join(fuzztestDir, d.name));

            for (const fuzzerDir of fuzzerDirs) {
                const fuzzerName = path.basename(fuzzerDir);
                const fuzzerInfo = await this.learnTestModule(fuzzerDir, projectName, fuzzerName, 'fuzztest');
                
                if (fuzzerInfo) {
                    structure.testDirs.push(fuzzerInfo);
                }
            }
        } catch (error) {
            // 忽略错误
        }
    }

    /**
     * 分析文件关系
     */
    private async analyzeFileRelations(structure: any): Promise<void> {
        // 1. 分析头文件与实现文件的关系
        for (const header of structure.sourceFiles.headers) {
            const correspondingImpl = structure.sourceFiles.impls.find((impl: any) => 
                impl.correspondingHeader === header.fileName ||
                impl.includes.includes(header.fileName)
            );
            
            if (correspondingImpl) {
                this.comprehensiveKnowledge.headerImplRelations.push({
                    projectName: structure.projectName,
                    header: header.fileName,
                    impl: correspondingImpl.fileName,
                    headerPath: header.relativePath,
                    implPath: correspondingImpl.relativePath
                });
            }
        }

        // 2. 分析测试文件与被测文件的关系
        for (const testDir of structure.testDirs) {
            for (const testFile of testDir.testFiles) {
                if (testFile.testedTarget) {
                    this.comprehensiveKnowledge.testTargetRelations.push({
                        projectName: structure.projectName,
                        testFile: testFile.fileName,
                        testedTarget: testFile.testedTarget,
                        testIncludes: testFile.includes
                    });
                }
            }
        }

        // 3. 分析 Mock 与原始类的关系
        for (const mockFile of structure.mockFiles) {
            const mockPattern = this.comprehensiveKnowledge.mockPatterns.find((m: any) => 
                m.filePath === mockFile.filePath
            );
            
            if (mockPattern && mockPattern.mockedTarget) {
                this.comprehensiveKnowledge.mockTargetRelations.push({
                    projectName: structure.projectName,
                    mockFile: mockFile.fileName,
                    mockedTarget: mockPattern.mockedTarget,
                    mockMethods: mockPattern.mockMethods.length
                });
            }
        }
    }

    /**
     * 分析关系（全局）
     */
    private analyzeRelationships(): void {
        Logger.info('\n📊 分析全局关系...');
        
        // 构建包含关系图
        this.buildIncludeGraph();
        
        // 构建依赖关系图
        this.buildDependencyGraph();
        
        Logger.info(`  ✓ 包含关系: ${this.comprehensiveKnowledge.includeGraph.length}`);
        Logger.info(`  ✓ 依赖关系: ${this.comprehensiveKnowledge.dependencyGraph.length}`);
    }

    /**
     * 构建包含关系图
     */
    private buildIncludeGraph(): void {
        // 分析哪些文件包含了哪些头文件
        const allFiles = [
            ...this.comprehensiveKnowledge.headerPatterns,
            ...this.comprehensiveKnowledge.implPatterns
        ];

        for (const file of allFiles) {
            for (const include of file.includes) {
                this.comprehensiveKnowledge.includeGraph.push({
                    from: file.fileName,
                    to: include,
                    projectName: file.projectName
                });
            }
        }
    }

    /**
     * 构建依赖关系图
     */
    private buildDependencyGraph(): void {
        // 从 BUILD.gn 中提取依赖关系
        for (const structure of this.comprehensiveKnowledge.projectStructures) {
            for (const buildFile of structure.buildFiles) {
                for (const dep of buildFile.deps) {
                    this.comprehensiveKnowledge.dependencyGraph.push({
                        from: buildFile.relativePath,
                        to: dep,
                        type: 'internal',
                        projectName: structure.projectName
                    });
                }
                
                for (const dep of buildFile.externalDeps) {
                    this.comprehensiveKnowledge.dependencyGraph.push({
                        from: buildFile.relativePath,
                        to: dep,
                        type: 'external',
                        projectName: structure.projectName
                    });
                }
            }
        }
    }

    // ========== 辅助提取方法 ==========

    private extractClasses(content: string): string[] {
        const classes: string[] = [];
        const classRegex = /class\s+(\w+)/g;
        let match;
        while ((match = classRegex.exec(content)) !== null) {
            classes.push(match[1]);
        }
        return [...new Set(classes)];
    }

    private extractFunctions(content: string): string[] {
        const functions: string[] = [];
        const funcRegex = /(?:virtual\s+)?\w+\s+(\w+)\s*\([^)]*\)/g;
        let match;
        let count = 0;
        while ((match = funcRegex.exec(content)) !== null && count < 50) {
            functions.push(match[1]);
            count++;
        }
        return [...new Set(functions)];
    }

    private extractIncludes(content: string): string[] {
        const includes: string[] = [];
        const includeRegex = /#include\s+[<"]([^>"]+)[>"]/g;
        let match;
        while ((match = includeRegex.exec(content)) !== null) {
            includes.push(match[1]);
        }
        return includes;
    }

    private extractNamespaces(content: string): string[] {
        const namespaces: string[] = [];
        const namespaceRegex = /namespace\s+(\w+)/g;
        let match;
        while ((match = namespaceRegex.exec(content)) !== null) {
            namespaces.push(match[1]);
        }
        return [...new Set(namespaces)];
    }

    private extractTestClasses(content: string): string[] {
        const classes: string[] = [];
        const classRegex = /class\s+(\w+)\s*:\s*public/g;
        let match;
        while ((match = classRegex.exec(content)) !== null) {
            classes.push(match[1]);
        }
        return classes;
    }

    private extractTestCases(content: string): any[] {
        const testCases: any[] = [];
        const testCaseRegex = /HWTEST_F\((\w+),\s*(\w+),\s*([^)]+)\)/g;
        let match;
        while ((match = testCaseRegex.exec(content)) !== null) {
            testCases.push({
                testClass: match[1],
                testName: match[2],
                testSize: match[3]
            });
        }
        return testCases;
    }

    private extractImplementedFunctions(content: string): string[] {
        const functions: string[] = [];
        const funcRegex = /\w+::\w+\s*\([^)]*\)/g;
        let match;
        let count = 0;
        while ((match = funcRegex.exec(content)) !== null && count < 30) {
            functions.push(match[0]);
            count++;
        }
        return functions;
    }

    private extractUsedMocks(content: string): string[] {
        const mocks: string[] = [];
        const mockRegex = /(?:NiceMock|StrictMock)<([^>]+)>/g;
        let match;
        while ((match = mockRegex.exec(content)) !== null) {
            mocks.push(match[1]);
        }
        return [...new Set(mocks)];
    }

    private extractMockMethods(content: string): string[] {
        const methods: string[] = [];
        const methodRegex = /MOCK_METHOD\d?\([^)]+\)/g;
        let match;
        while ((match = methodRegex.exec(content)) !== null) {
            methods.push(match[0]);
        }
        return methods;
    }

    private extractArrayField(content: string, fieldName: string): string[] {
        const regex = new RegExp(`${fieldName}\\s*=\\s*\\[([^\\]]+(?:\\[[^\\]]*\\][^\\]]*)*?)\\]`, 'is');
        const match = content.match(regex);
        
        if (!match) return [];
        
        const arrayContent = match[1];
        const items: string[] = [];
        
        const itemRegex = /"([^"]+)"/g;
        let itemMatch;
        
        while ((itemMatch = itemRegex.exec(arrayContent)) !== null) {
            items.push(itemMatch[1]);
        }
        
        return items;
    }

    private extractTargetTypes(content: string): string[] {
        const types: string[] = [];
        const typeRegex = /ohos_(\w+)\(/g;
        let match;
        while ((match = typeRegex.exec(content)) !== null) {
            types.push(match[1]);
        }
        return [...new Set(types)];
    }

    private guessCorrespondingHeader(filePath: string, content: string): string | null {
        const baseName = path.basename(filePath, '.cpp').replace(/_impl$/, '');
        const includes = this.extractIncludes(content);
        
        // 查找对应的头文件
        for (const include of includes) {
            if (include.includes(baseName)) {
                return include;
            }
        }
        
        return null;
    }

    private guessTestedTarget(filePath: string, content: string): string | null {
        const testFileName = path.basename(filePath, '_test.cpp');
        const includes = this.extractIncludes(content);
        
        // 查找被测试的头文件
        for (const include of includes) {
            if (include.includes(testFileName) && !include.includes('test')) {
                return include;
            }
        }
        
        return null;
    }

    private guessMockedTarget(filePath: string, content: string): string | null {
        const mockFileName = path.basename(filePath).replace(/_mock/, '').replace(/mock_/, '');
        const includes = this.extractIncludes(content);
        
        // 查找被Mock的头文件
        for (const include of includes) {
            if (include.includes(mockFileName.replace('.cpp', '').replace('.h', ''))) {
                return include;
            }
        }
        
        return null;
    }

    /**
     * 保存全面知识
     */
    public async save(savePath: string): Promise<void> {
        const data = {
            ...this.comprehensiveKnowledge,
            learnedAt: new Date().toISOString(),
            projectCount: this.discoverProjects().length,
            version: '3.0-comprehensive'
        };

        fs.writeFileSync(savePath, JSON.stringify(data, null, 2), 'utf-8');
        Logger.info(`\n💾 全面知识已保存: ${savePath}`);
        
        const stats = fs.statSync(savePath);
        const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
        Logger.info(`📊 知识库大小: ${sizeMB} MB`);
    }

    /**
     * 获取全面知识
     */
    public getComprehensiveKnowledge(): any {
        return this.comprehensiveKnowledge;
    }
}

